﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using StackExchange.Redis;
using System.IO;
using System.Net;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Compression;

namespace RedisSamples
{
    public class RedisHelper
    {
        private static string _connStr = ConfigurationManager.AppSettings["RedisConnStr"] ?? "127.0.0.1:7000";
        private const int BufferSize = 64 * 1024; //64kB
        private static ConnectionMultiplexer _conn;
        static RedisHelper()
        {
            _conn = ConnectionMultiplexer.Connect(_connStr);
        }
        /// <summary>
        /// 基本数据类型的设置
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbIndex">数据库索引</param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool Set<T>(int dbIndex,string key,T value)
        {
           return _conn.GetDatabase(dbIndex).StringSet(key, value.ToString());
        }
        /// <summary>
        /// 获取值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbIndex">数据库索引</param>
        /// <param name="key">key</param>
        /// <returns></returns>
        public static T Get<T>(int dbIndex, string key)
        {
            RedisValue val = _conn.GetDatabase(dbIndex).StringGet(key);
            return (T)Convert.ChangeType(val.ToString(), typeof(T));
        }
        /// <summary>
        /// 获取字符串
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要读取的Key</param>
        /// <returns>String格式的字符串</returns>
        public static string StringGet(int dbIndex,string key)
        {
            return _conn.GetDatabase(dbIndex).StringGet(key);
        }
        /// <summary>
        /// 设置字符串
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要设置的Key</param>
        /// <param name="value">要设置的Value</param>
        /// <returns></returns>
        public static bool StringSet(int dbIndex, string key,string value)
        {
            return _conn.GetDatabase(dbIndex).StringSet(key, value);
        }
        /// <summary>
        /// 删除Key
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要删除的Key</param>
        /// <returns></returns>
        public static bool KeyDel(int dbIndex, string key)
        {
            return _conn.GetDatabase(dbIndex).KeyDelete(key);
        }
        /// <summary>
        /// 获取Hash的值
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要读取的Key</param>
        /// <returns></returns>
        public static HashEntry[] HashGet(int dbIndex, string key)
        {
            return _conn.GetDatabase(dbIndex).HashGetAll(key); 
        }
        /// <summary>
        /// 设置Hash的值
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要读取的Key</param>
        /// <param name="field">hash对应的name</param>
        /// <param name="value">hash对应的value</param>
        public static void HashSet(int dbIndex,string key,string field,string value)
        {
            _conn.GetDatabase(dbIndex).HashSet(key, new HashEntry[] { new HashEntry(field, value) });
        }
        public static bool HashItemDel(int dbIndex,string key, string hashField)
        {
           return _conn.GetDatabase(dbIndex).HashDelete(key, hashField);
        }
        /// <summary>
        /// 设置List的值
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要设置的Key</param>
        /// <param name="values">要设置的值，多个用空格分隔</param>
        public static void SetList(int dbIndex,string key,string values)
        {
            List<RedisValue> list = new List<RedisValue>();
            foreach(string s in values.Split(' '))
            {
                list.Add(s);
            }
            _conn.GetDatabase(dbIndex).ListRightPush(key, list.ToArray());
        }
        /// <summary>
        /// 将值加入到List中
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">对应list的Key</param>
        /// <param name="values"></param>
        public static void SetList(int dbIndex, string key, RedisValue[] values)
        {
            _conn.GetDatabase(dbIndex).ListRightPush(key, values);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="dbIndex"></param>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public static void ListItemDelete(int dbIndex,string key,string value)
        {
            _conn.GetDatabase(dbIndex).ListRemove(key, value);
        }
        /// <summary>
        /// 获取List的值
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要读取的Key</param>
        /// <returns></returns>
        public static RedisValue[] GetList(int dbIndex,string key)
        {
            return _conn.GetDatabase(dbIndex).ListRange(key);
        }
        /// <summary>
        /// 获取特定范围内容List的内容
        /// </summary>
        /// <param name="dbIndex"></param>
        /// <param name="key"></param>
        /// <param name="start"></param>
        /// <param name="stop"></param>
        /// <returns></returns>
        public static RedisValue[] GetList(int dbIndex, string key,long start,long stop)
        {
            return _conn.GetDatabase(dbIndex).ListRange(key,start,stop);
        }
        /// <summary>
        /// 添加值到Set
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要设置的Key</param>
        /// <param name="value">要设置的Value</param>
        /// <returns></returns>
        public static bool AddSet(int dbIndex,string key,string value)
        {
           return _conn.GetDatabase(dbIndex).SetAdd(key,value);
        }
        /// <summary>
        /// 获取Set里面的值
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">要获取的Key</param>
        /// <returns></returns>
        public static RedisValue[] GetSet(int dbIndex,string key)
        {
            return _conn.GetDatabase(dbIndex).SetMembers(key);
        }
        /// <summary>
        /// Set集合操作
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="setList">要操作的key们</param>
        /// <param name="operate">操作方式</param>
        /// <returns></returns>
        public static RedisValue[] UnionSet(int dbIndex, string setList, SetOperation operate)
        {
            List<RedisKey> list = new List<RedisKey>();
            foreach (string s in setList.Split(' '))
            {
                list.Add(s);
            }
           return _conn.GetDatabase(dbIndex).SetCombine(operate, list.ToArray());
        }
        /// <summary>
        /// 集合中元素的一处
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">集合的key</param>
        /// <param name="item">集合中的某一项</param>
        public static void SetItemDelete(int dbIndex, string key, string item)
        {
            _conn.GetDatabase(dbIndex).SetRemove(key, item);
        }
        /// <summary>
        /// 保存文件
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">文件对应的key</param>
        /// <param name="fileName">文件所在位置</param>
        public static void FileInsert(int dbIndex, string key, string fileName,bool compress=false)
        {
            using (BinaryReader br = new BinaryReader(File.OpenRead(fileName)))
            {
                //把内容读出来
                byte[] b = new byte[br.BaseStream.Length];
                br.Read(b, 0, b.Length);
                if (compress) { 
                    _conn.GetDatabase(dbIndex).StringSet(key, Compress(b));
                }
                else
                {
                    _conn.GetDatabase(dbIndex).StringSet(key, b);
                }
            }
        }
        /// <summary>
        /// 读取文件
        /// </summary>
        /// <param name="dbIndex">数据库id</param>
        /// <param name="key">文件对于的key</param>
        /// <param name="fileName">保存的目标位置</param>
        public static void FileSaveAs(int dbIndex, string key, string fileName, bool compress=false)
        {
            RedisValue v = _conn.GetDatabase(dbIndex).StringGet(key);
            using (BinaryWriter bw = new BinaryWriter(File.OpenWrite(fileName)))
            {
                if (compress) { 
                    bw.Write(Decompress((byte[])v));
                }
                else
                {
                    bw.Write((byte[])v);
                }
                bw.Flush();
                bw.Close();
            }
        }
        /// <summary>
        /// 压缩
        /// </summary>
        /// <param name="inputData"></param>
        /// <returns></returns>
        private static byte[] Compress(byte[] inputData)
        {
            using (var ms = new MemoryStream())
            {
                using (var gzs = new BufferedStream(new GZipStream(ms, CompressionMode.Compress), BufferSize))
                {
                    gzs.Write(inputData, 0, inputData.Length);
                }
                return ms.ToArray();
            }
        }
        /// <summary>
        /// 解压缩
        /// </summary>
        /// <param name="inputData">The input data.</param>
        private static byte[] Decompress(byte[] inputData)
        {
            using (var cMs = new MemoryStream(inputData))
            {
                using (var dMs = new MemoryStream())
                {
                    using (var gzs = new BufferedStream(new GZipStream(cMs, CompressionMode.Decompress), BufferSize))
                    {
                        gzs.CopyTo(dMs);
                    }
                    return dMs.ToArray();
                }
            }
        }
        /// <summary>
        /// 清除掉所有的key
        /// </summary>
        public static void ClearAllKeys()
        {
            IServer server = _conn.GetServer(_conn.GetEndPoints().First<EndPoint>());
            //集群模式
            if (server.ServerType == ServerType.Cluster)
            {
                foreach(EndPoint point in _conn.GetEndPoints())
                {
                    foreach (var key in _conn.GetServer(point).Keys())
                    {
                        _conn.GetDatabase().KeyDelete(key);
                    }
                }
            }
            else
            {
                for (int i = 0; i < 16; i++)
                { 
                    foreach (var key in _conn.GetServer(_conn.GetEndPoints().First<EndPoint>()).Keys(i))
                    {
                        _conn.GetDatabase(i).KeyDelete(key);
                    }
                }
            }
            
        }
        /// <summary>
        /// 获取当前客户端的操作对象
        /// </summary>
        /// <returns></returns>
        public static ConnectionMultiplexer GetConn()
        {
            return _conn;
        }
        public static RedisType GetRedisType(int dbIndex,string key)
        {
           return _conn.GetDatabase(dbIndex).KeyType(key);
        }
    }
}
